package com.taldh.netty.learning.singleThreadReactor;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;

/**
 * date 2020/8/11
 *
 * @author 袁小黑
 * @version 1.0.0
 **/

public class Reactor implements Runnable{

    public ServerSocketChannel serverSocket;
    public Selector selector;

    Reactor(SocketAddress local) throws IOException {
        selector = Selector.open();
        serverSocket = ServerSocketChannel.open();
        this.serverSocket.bind(local);
        serverSocket.configureBlocking(false);
        SelectionKey sk = serverSocket.register(selector, SelectionKey.OP_ACCEPT); //注册accept事件
        sk.attach(new Acceptor()); //调用Acceptor()为回调方法
    }

    @Override
    public void run() {
        while (!Thread.interrupted()) {
            try {
                if (selector.select()>0) {
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    for (SelectionKey selectionKey : selectionKeys) {
                        dispatchKey(selectionKey);
                    }
                    selectionKeys.clear();
                }
            } catch (IOException e) {
            }
        }
    }

    private void dispatchKey(SelectionKey selectionKey) {
        Object r = selectionKey.attachment(); //调用SelectionKey绑定的调用对象
        if (r instanceof Runnable)
            ((Runnable)r).run();
    }

    class Acceptor implements Runnable { // inner
        public void run() {
            try {
                SocketChannel c = serverSocket.accept();
                if (c != null)
                    new Handler(selector, c);
            }
            catch(IOException ex) { /* ... */ }
        }
    }

    public static void main(String[] args) throws IOException {
        new Thread(new Reactor(new InetSocketAddress("127.0.0.1", 9001)));
    }
}


class Handler {
    final SocketChannel socket;
    final SelectionKey sk;
    ByteBuffer input = ByteBuffer.allocate(1024);
    ByteBuffer output = ByteBuffer.allocate(1024);
    static final int READING = 0, SENDING = 1;
    int state = READING;

    Handler(Selector sel, SocketChannel c) throws IOException {
        socket = c;
        c.configureBlocking(false);
        // Optionally try first read now
        sk = socket.register(sel, 0);
        sk.attach(this); //将Handler绑定到SelectionKey上
        sk.interestOps(SelectionKey.OP_READ);
        sel.wakeup();
    }
    boolean inputIsComplete() {
        /* ... 半包粘包的问题 */
        return false;
    }
    boolean outputIsComplete() {
        /* ...半包粘包的问题 */
        return false;
    }
    void process() { /* ... */ }

    public void run() {
        try {
            if (state == READING) read();
            else if (state == SENDING) send();
        } catch (IOException ex) { /* ... */ }
    }

    void read() throws IOException {
        socket.read(input);
        if (inputIsComplete()) {
            process();
            state = SENDING;
            // Normally also do first write now
            sk.interestOps(SelectionKey.OP_WRITE);
        }
    }
    void send() throws IOException {
        socket.write(output);
        if (outputIsComplete()) sk.cancel();
    }
}